package com.rivues.util.iface.report;

import java.util.List;
import java.util.Map;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rivues.core.RivuDataContext;
import com.rivues.module.platform.web.bean.TaskInfo;
import com.rivues.module.platform.web.model.AnalyzerReport;
import com.rivues.module.platform.web.model.Auth;
import com.rivues.module.platform.web.model.DataDic;
import com.rivues.module.platform.web.model.DicAnalyzerReport;
import com.rivues.module.platform.web.model.JobDetail;
import com.rivues.module.platform.web.model.Role;
import com.rivues.module.platform.web.model.User;
import com.rivues.module.report.web.model.PublishedReport;
import com.rivues.module.report.web.model.TaskReport;
import com.rivues.module.report.web.model.TaskReportInfo;
import com.rivues.util.RivuTools;
import com.rivues.util.exception.DicExistEception;
import com.rivues.util.exception.DicNotExistException;
import com.rivues.util.exception.ReportException;
import com.rivues.util.exception.RivuException;
import com.rivues.util.serialize.JSON;
import com.rivues.util.service.cache.CacheHelper;

@SuppressWarnings("unchecked")
public class DatabaseReportImpl implements Report{
	private final Logger logger = LoggerFactory.getLogger(DatabaseReportImpl.class);
	/**
	 * 
	 */
	private static final long serialVersionUID = 6609610372829684904L;

	@Override
	public List<PublishedReport> getReportList(String dicid , String orgi , User user  , String tabid,String reporttype) {
		DetachedCriteria criteria = DetachedCriteria
				.forClass(PublishedReport.class)
				.add(Restrictions.or(
						Restrictions.eq("creater", user.getId()),
						Restrictions.and(
								Restrictions
										.eq("status",
												RivuDataContext.ReportStatusEnum.AVAILABLE
														.toString()),
								Restrictions
										.eq("publishedtype",
												RivuDataContext.ReportStatusEnum.PUBLISHED
														.toString())))
				)
				.add(Restrictions.eq("orgi", orgi))
				.add(Restrictions.eq("tabtype", tabid))
				.add(Restrictions.eq("dicid", dicid))
				.addOrder(Order.asc("createtime"));
		if(reporttype!=null){
			criteria.add(Restrictions.eq("reporttype", reporttype));
		}
		return RivuDataContext.getService().findAllByCriteria(criteria);
	}
	
	/**
	 * 
	 */
	@Override
	public List<PublishedReport> searchReportList(String dicid,String type , String name , String orgi , User user  , String tabid,String reporttype  , String pritype) {
		DetachedCriteria criteria = DetachedCriteria
				.forClass(PublishedReport.class)
				.add(Restrictions.or(
						Restrictions.eq("creater", user.getId()),
						Restrictions.and(
								Restrictions
										.eq("status",
												RivuDataContext.ReportStatusEnum.AVAILABLE
														.toString()),
								Restrictions
										.eq("publishedtype",
												RivuDataContext.ReportStatusEnum.PUBLISHED
														.toString())))
				)
				.add(Restrictions.eq("orgi", orgi))
				.addOrder(Order.asc("createtime"));
		if(pritype!=null){
			if(pritype.equals(RivuDataContext.SearchType.CREATE.toString())){
				criteria.add(Restrictions.eq("creater", user.getId()));
			}
			if(pritype.equals(RivuDataContext.SearchType.SAVE.toString())){
				criteria.add(Restrictions.and(Restrictions.eq("reporttype", reporttype), Restrictions.eq("creater", user.getId())) );
			}	
		}else{
			criteria.add(Restrictions.eq("tabtype", tabid)) ;
			if(!(type!=null && type.equals(RivuDataContext.SearchType.ALL.toString()))){
				criteria.add(Restrictions.eq("dicid", dicid)) ;
			}
		}
		if(name!=null && name.length()>0){
			criteria.add(Restrictions.like("name", name , MatchMode.ANYWHERE)) ;
		}
		if(reporttype!=null){
			criteria.add(Restrictions.eq("reporttype", reporttype));
		}
		
		return RivuDataContext.getService().findAllByCriteria(criteria);
	}
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public PublishedReport getReportByID(User user, String orgi , String reportid) throws ReportException{
		PublishedReport report = null;
		if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportid , user , false), orgi)==null){
			if(!reportid.startsWith(RivuDataContext.JOB_REPORT_ID)){	//标识 是 从JOB加进来的 Report
				List<PublishedReport> reportList = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(PublishedReport.class).add(Restrictions.eq("orgi",orgi)).add(Restrictions.eq("id",reportid)));
				if(reportList.size() > 0 ){
					//PublishedReport report = (PublishedReport) RivuDataContext.getService().getIObjectByPK(PublishedReport.class, reportid) ;
					report = reportList.get(0) ;
					CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user , false), report, orgi) ;
				}
			}else{
				/**
				 * 从JOBDETAIL加入进来的报表， ID的规则为 JOB_{job id}_{report id}
				 */
				String jobid = reportid.substring(reportid.indexOf("_")+1,reportid.lastIndexOf("_")) ;
				JobDetail jobDetail = (JobDetail) RivuDataContext.getService().getIObjectByPK(JobDetail.class, jobid) ;
				
				TaskReportInfo taskReportInfo = null ;
				TaskInfo taskinfo = null;
				if(jobDetail.getTaskinfo()!=null && jobDetail.getTaskinfo().length()>0){
					taskinfo = JSON.parseObject(jobDetail.getTaskinfo(), TaskInfo.class) ;
					taskReportInfo = (TaskReportInfo)taskinfo.getTargetObject();
				}else{
					taskinfo = new TaskInfo();
				}
				if(taskReportInfo == null){
					taskReportInfo = new TaskReportInfo();
				}
				for(TaskReport tr : taskReportInfo.getReportList()){
					if(reportid.equals(tr.getReportid())){
						report = tr.getPublishedReport() ;
						CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user , false), report, orgi) ;
						break ;
					}
				}
			}
		}
		report = (PublishedReport) CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportid , user , false), orgi);
		if(report==null){
    		throw new ReportException("REPORT_ERR_00001");
    	}
		return report;
	}
	
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public boolean getReport(User user, String orgi , String reportid) {
		return CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportid , user , false), orgi)==null;
	}
	
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public void putReport(PublishedReport report ,User user) {
		CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user, false), report, report.getOrgi()) ;
	}
	
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public PublishedReport getReportByID(User user, String orgi , String reportid , boolean userSessionID) {
		if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportid , user, userSessionID), orgi)==null){
			PublishedReport report = (PublishedReport) RivuDataContext.getService().getIObjectByPK(PublishedReport.class, reportid) ;
			CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() ,  user, userSessionID), report, orgi) ;
		}
		return (PublishedReport) CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportid ,  user, userSessionID), orgi);
	}
	
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public PublishedReport getReportByIDFromDB(User user, String orgi , String reportid) {
		return (PublishedReport) RivuDataContext.getService().getIObjectByPK(PublishedReport.class, reportid) ;
	}

	@Override
	public boolean createReport(PublishedReport report , User user) {
		if(report.getReportcontent()==null || report.getReportcontent().length()==0){
			report.setReportcontent(JSON.toJSONString(new AnalyzerReport())) ;
		}
		RivuDataContext.getService().saveIObject(report) ;
		return true;
	}
	/**
	 * 从数据库中获取 目录列表
	 */
	@Override
	public List<DataDic> getReportDicList(String orgi , User user , String parentid , String tabid) {
		// TODO Auto-generated method stub
		return RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(DataDic.class).add(Restrictions.eq("code",RivuDataContext.ReportTypeEnum.REPORT.toString())).add(Restrictions.or(Restrictions.eq("creater",user.getId()), Restrictions.and(Restrictions.eq("status",RivuDataContext.ReportStatusEnum.AVAILABLE.toString()), Restrictions.eq("publishedtype",RivuDataContext.ReportStatusEnum.PUBLISHED.toString())) ) ).add(Restrictions.eq("orgi",orgi)).add(Restrictions.eq("tabtype",tabid)).add(Restrictions.eq("parentid",parentid)));
	}
	/**
	 * 从数据库中获取 目录列表
	 */
	@Override
	public List<DataDic> getAllReportDicList(String orgi , User user , String tabid) {
		DetachedCriteria criteria =null;
		if (DataDic.TABTYPE_PUB.equals(tabid)){
			 criteria = DetachedCriteria.forClass(DataDic.class).add(Restrictions.eq("code",RivuDataContext.ReportTypeEnum.REPORT.toString())).add(Restrictions.or(Restrictions.eq("creater",user.getId()), Restrictions.and(Restrictions.eq("status",RivuDataContext.ReportStatusEnum.AVAILABLE.toString()), Restrictions.eq("publishedtype",RivuDataContext.ReportStatusEnum.PUBLISHED.toString())) ) ).add(Restrictions.eq("orgi",orgi)).addOrder(Order.asc("createtime"));
		} else {
			 criteria = DetachedCriteria.forClass(DataDic.class).add(Restrictions.eq("code",RivuDataContext.ReportTypeEnum.REPORT.toString())).add(Restrictions.eq("creater", user.getId())).add(Restrictions.eq("orgi",orgi)).addOrder(Order.asc("createtime"));
		}
		if(tabid!=null){
			criteria.add(Restrictions.eq("tabtype",tabid));
		}
		return RivuDataContext.getService().findAllByCriteria(criteria);
		
	}
	/**
	 * 保存目录
	 */
	@Override
	public void createReportDic(DataDic dataDic , User user) throws DicExistEception {
		RivuDataContext.getService().saveIObject(dataDic) ;
	}

	@Override
	public DataDic getReportDic(String id , String orgi , User user) throws DicNotExistException {
		return (DataDic) RivuDataContext.getService().getIObjectByPK(DataDic.class, id);
	}

	@Override
	public void rmDataDicByID(User user, String orgi, String dicid) throws DicNotExistException {
		DataDic dataDic = new DataDic() ;
		dataDic.setId(dicid) ;
		RivuDataContext.getService().deleteIObject(dataDic) ;
	}
	
	
	@Override
	public boolean updateReport(PublishedReport report, User user) throws ReportException {
		// TODO Auto-generated method stub
		
		if(!report.getId().startsWith(RivuDataContext.JOB_REPORT_ID)){
			/**
			 * 得先将Report序列化
			 */
			
			
			if(RivuDataContext.ReportTypeEnum.REPORT.toString().equals(report.getReporttype())){
				Map<String , Object> requestParamValues = report.getReport().getRequestParamValues() ;
				report.getReport().setRequestParamValues(null) ;
				report.setReportcontent(JSON.toJSONString(report.getReport())) ;
				report.getReport().setRequestParamValues(requestParamValues) ;
			}
				
			
			/**
			 * 序列化结束
			 */
			RivuDataContext.getService().updateIObject(report) ;
			PublishedReport cache_rpt = (PublishedReport)CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(report.getId() ,  user, false), report.getOrgi());
			if(cache_rpt!=null){
				report.setReportcontent(cache_rpt.getReportcontent());
			}
			if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(report.getId() , user, false) , report.getOrgi())!=null){
				CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user, false), report, report.getOrgi()) ;
			}
			if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(report.getId() , user, true) , report.getOrgi())!=null){
				CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user, true), report, report.getOrgi()) ;
			}
		}else{
			/**
			 * 从JOBDETAIL加入进来的报表， ID的规则为 JOB_{job id}_{report id}
			 */
			String jobid = report.getId().substring(report.getId().indexOf("_")+1,report.getId().lastIndexOf("_")) ;
			JobDetail jobDetail = (JobDetail) RivuDataContext.getService().getIObjectByPK(JobDetail.class, jobid) ;
			
			TaskReportInfo taskReportInfo = null ;
			TaskInfo taskinfo = null;
			if(jobDetail.getTaskinfo()!=null && jobDetail.getTaskinfo().length()>0){
				taskinfo = JSON.parseObject(jobDetail.getTaskinfo(), TaskInfo.class) ;
				taskReportInfo = (TaskReportInfo)taskinfo.getTargetObject();
			}else{
				taskinfo = new TaskInfo();
			}
			if(taskReportInfo == null){
				taskReportInfo = new TaskReportInfo();
			}
			for(TaskReport tr : taskReportInfo.getReportList()){
				if(report.getId().equals(tr.getReportid())){
					AnalyzerReport rpt = JSON.parseObject(report.getReportcontent(), AnalyzerReport.class);
					tr.setPublishedReport(report) ;
					break ;
				}
			}
			taskinfo.setTargetObject(taskReportInfo);
			jobDetail.setTaskinfo(JSON.toJSONString(taskinfo)) ;
			RivuDataContext.getService().updateIObject(jobDetail) ;
		}
		return true;
	}
	
	
	@Override
	public void updateReportDic(DataDic dataDic, User user)
			throws DicExistEception {
		RivuDataContext.getService().updateIObject(dataDic) ;
		
	}
	@Override
	public int getCount(DetachedCriteria criteria,User user) {
		// TODO Auto-generated method stub
		return RivuDataContext.getService().getCountByCriteria(criteria);
	}
	@Override
	public void rmReportByID(String reportId, User user, String orgi)
			throws ReportException {
		if(reportId!=null && !reportId.startsWith(RivuDataContext.JOB_REPORT_ID)){
			PublishedReport report = (PublishedReport)RivuDataContext.getService().getIObjectByPK(PublishedReport.class, reportId);
			
			if("plan".equals(report.getReporttype())){
				List<JobDetail> jobs = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(JobDetail.class).add(Restrictions.eq("taskid",reportId)).add(Restrictions.eq("orgi",orgi)));
				if(jobs.size()>0){
					for (int i = 0; i < jobs.size(); i++) {
						RivuDataContext.getService().deleteIObject(jobs.get(i));
					}
				}
			}
			RivuDataContext.getService().deleteIObject(report);
		}
		if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(reportId , user , false), orgi)!=null){
			CacheHelper.getDistributedCacheBean().delete(RivuTools.genReportCacheID(reportId , user , false), orgi) ;
		}
	}
	
	/**
	 * 按照ID获取报表，同时将该报表放入到缓存中以备用
	 */
	@Override
	public PublishedReport getReportByName(User user, String orgi , String reportname) {
		PublishedReport report = null ;
		List<PublishedReport> reportList = RivuDataContext.getService().findAllByCriteria(DetachedCriteria.forClass(PublishedReport.class).add(Restrictions.eq("title",reportname)).add(Restrictions.eq("orgi",orgi)));
		if(reportList!=null && reportList.size()>0){
			report = reportList.get(0) ;
			if(CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(report.getId() , user, true), orgi)==null){
				
				CacheHelper.getDistributedCacheBean().put(RivuTools.genReportCacheID(report.getId() , user, true), report, orgi) ;
			}
		}
		return report!=null ? (PublishedReport) CacheHelper.getDistributedCacheBean().getCacheObject(RivuTools.genReportCacheID(report.getId() , user, true), orgi) : null ;
	}

	@Override
	public List<PublishedReport> getReportList(String targetReportid,
			String orgi, String tabid, String reporttype) {
		DetachedCriteria criteria = DetachedCriteria.forClass(PublishedReport.class).add(Restrictions.eq("orgi",orgi)).add(Restrictions.eq("targetReport", targetReportid));
		if(reporttype!=null){
			criteria.add(Restrictions.eq("reporttype", reporttype));
		}
		if(reporttype!=null){
			criteria.add(Restrictions.eq("tabtype", tabid));
		}
		return RivuDataContext.getService().findAllByCriteria(criteria);
	}

}
